home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_Tix.idb / usr / freeware / lib / tix4.1 / PanedWin.tcl.z / PanedWin.tcl
Encoding:
Text File  |  1999-01-26  |  26.7 KB  |  1,182 lines

  1. # PanedWin.tcl --
  2. #
  3. #    This file implements the TixPanedWindow widget
  4. #
  5. # Copyright (c) 1996, Expert Interface Technologies
  6. #
  7. # See the file "license.terms" for information on usage and redistribution
  8. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  9. #
  10.  
  11.  
  12. tixWidgetClass tixPanedWindow {
  13.     -classname TixPanedWindow
  14.     -superclass tixPrimitive
  15.     -method {
  16.     add delete forget manage panecget paneconfigure panes setsize
  17.     }
  18.     -flag {
  19.     -command -dynamicgeometry -handleactivebg -handlebg -orient
  20.     -orientation -panebd -paneborderwidth -panerelief
  21.     -separatoractivebg -separatorbg
  22.     }
  23.     -static {
  24.     -orientation
  25.     }
  26.     -configspec {
  27.     {-command command Command ""}
  28.     {-dynamicgeometry dynamicGeometry DynamicGeometry 1 tixVerifyBoolean}
  29.     {-handleactivebg handleActiveBg HandleActiveBg #ececec}
  30.     {-handlebg handleBg Background #d9d9d9}
  31.     {-orientation orientation Orientation vertical}
  32.     {-paneborderwidth paneBorderWidth PaneBorderWidth 1}
  33.     {-panerelief paneRelief PaneRelief raised}
  34.     {-separatoractivebg separatorActiveBg SeparatorActiveBg red}
  35.     {-separatorbg separatorBg Background #d9d9d9}
  36.     }
  37.     -alias {
  38.     {-panebd -paneborderwidth}
  39.     {-orient -orientation}
  40.     }
  41. }
  42.  
  43. #----------------------------------------------------------------------
  44. # ClassInitialization:
  45. #----------------------------------------------------------------------
  46.  
  47. proc tixPanedWindow:InitWidgetRec {w} {
  48.     upvar #0 $w data
  49.  
  50.     tixChainMethod $w InitWidgetRec
  51.  
  52.     set data(items)       ""
  53.     set data(nItems)      0
  54.     set data(totalsize)   0
  55.     set data(movePending) 0
  56.  
  57.     set data(repack)      0
  58.     set data(counter)     0
  59.  
  60.     set data(maxReqW)     1
  61.     set data(maxReqH)     1
  62. }
  63.  
  64. proc tixPanedWindow:ConstructWidget {w} {
  65.     upvar #0 $w data
  66.  
  67.     tixChainMethod $w ConstructWidget
  68.     # Do nothing
  69. }
  70.  
  71. proc tixPanedWindow:SetBindings {w} {
  72.     upvar #0 $w data
  73.  
  74.     tixChainMethod $w SetBindings
  75.  
  76.     bind $w <Configure> [list tixPanedWindow:MasterGeomProc $w ""]
  77. }
  78.  
  79. #----------------------------------------------------------------------
  80. # ConfigOptions:
  81. #----------------------------------------------------------------------
  82. proc tixPanedWindow:config-handlebg {w arg} {
  83.     upvar #0 $w data
  84.  
  85.     for {set i 1} {$i < $data(nItems)} {incr i} {
  86.     $data(btn,$i) config -bg $arg
  87.     }
  88. }
  89.  
  90. #----------------------------------------------------------------------
  91. # PublicMethods:
  92. #----------------------------------------------------------------------
  93.  
  94.  
  95. # method: add
  96. #
  97. #    Adds a new pane into the PanedWindow.
  98. #
  99. # options -size -max -min -allowresize
  100. #
  101. proc tixPanedWindow:add {w name args} {
  102.     upvar #0 $w data
  103.  
  104.     if {[winfo exists $w.$name] && !$data($name,forgotten)} {
  105.     error "Pane $name is already managed"
  106.     }
  107.     # Step 1: Parse the options to get the children's size options
  108.  
  109.     # The default values
  110.     #
  111.     if [info exists data($name,forgotten)] {
  112.     set option(-size)        $data($name,size)
  113.     set option(-min)         $data($name,min)
  114.     set option(-max)         $data($name,max)
  115.     set option(-allowresize) $data($name,allowresize)
  116.     set option(-expand)      $data($name,expand)
  117.     } else {
  118.     set option(-size)        0
  119.     set option(-min)         0
  120.     set option(-max)         100000
  121.     set option(-allowresize) 1
  122.     set option(-expand)      0
  123.     }
  124.  
  125.     set option(-before)      ""
  126.     set option(-after)       ""
  127.     set option(-at)          ""
  128.     set validOpts {-after -allowresize -at -before -expand -max -min -size}
  129.  
  130.     tixHandleOptions option $validOpts $args
  131.  
  132.     set data($name,size)        $option(-size)
  133.     set data($name,rsize)       $option(-size)
  134.     set data($name,min)         $option(-min)
  135.     set data($name,max)         $option(-max)
  136.     set data($name,allowresize) $option(-allowresize)
  137.     set data($name,expand)      $option(-expand)
  138.     set data($name,forgotten)   0
  139.  
  140.     if {$data($name,expand) < 0} {
  141.     set data($name,expand) 0
  142.     }
  143.  
  144.     # Step 2: Add the frame and the separator (if necessary)
  145.     #
  146.     if {![winfo exist $w.$name]} {
  147.     # need to check because the frame may have been "forget'ten"
  148.     #
  149.     frame $w.$name -bd $data(-paneborderwidth) -relief $data(-panerelief)
  150.     }
  151.  
  152.     if {$option(-at) != ""} {
  153.     set at [tixGetInt $option(-at)]
  154.     if {$at < 0} {
  155.         set at 0
  156.     }
  157.     } elseif {$option(-after) != ""} {
  158.     set index [lsearch -exact $data(items) $option(-after)]
  159.     if {$index == -1} {
  160.         error "Pane $option(-after) doesn't exists"
  161.     } else {
  162.         set at [incr index]
  163.     }
  164.     } elseif {$option(-before) != ""} {
  165.     set index [lsearch -exact $data(items) $option(-before)]
  166.     if {$index == -1} {
  167.         error "Pane $option(-before) doesn't exists"
  168.     }
  169.     set at $index
  170.     } else {
  171.     set at end
  172.     }
  173.  
  174.     set data(items) [linsert $data(items) $at $name]    
  175.     incr data(nItems)
  176.  
  177.     if {$data(nItems) > 1} {
  178.     tixPanedWindow:AddSeparator $w
  179.     }
  180.     set data(w:$name) $w.$name
  181.  
  182.     # Step 3: Add the new frame. Adjust the window later (do when idle)
  183.     #
  184.     tixManageGeometry $w.$name "tixPanedWindow:ClientGeomProc $w"
  185.     bind $w.$name <Configure> \
  186.     [list tixPanedWindow:ClientGeomProc $w "" $w.$name]
  187.  
  188.     tixPanedWindow:RepackWhenIdle $w
  189.  
  190.     return $w.$name
  191. }
  192.  
  193. proc tixPanedWindow:manage {w name args} {
  194.     upvar #0 $w data
  195.  
  196.     if {![winfo exists $w.$name]} {
  197.     error "Pane $name does not exist"
  198.     }
  199.     if {!$data($name,forgotten)} {
  200.     error "Pane $name is already managed"
  201.     }
  202.     tixMapWindow $data(w:$name)
  203.     eval tixPanedWindow:add $w [list $name] $args
  204. }
  205.  
  206. proc tixPanedWindow:forget {w name} {
  207.     upvar #0 $w data
  208.  
  209.     if {![winfo exists $w.$name]} {
  210.     error "Pane $name does not exist"
  211.     }
  212.     if $data($name,forgotten) {
  213.     # It has already been forgotten
  214.     #
  215.     return
  216.     }
  217.  
  218.     set items ""
  219.     foreach item $data(items) {
  220.     if {$item != $name} {
  221.         lappend items $item
  222.     }
  223.     }
  224.     set data(items) $items
  225.     incr data(nItems) -1
  226.  
  227.     set i $data(nItems)
  228.     if {$i > 0} {
  229.     destroy $data(btn,$i)
  230.     destroy $data(sep,$i)
  231.     unset data(btn,$i)
  232.     unset data(sep,$i)
  233.     }
  234.     set data($name,forgotten) 1
  235.  
  236.     tixUnmapWindow $w.$name
  237.  
  238.     tixPanedWindow:RepackWhenIdle $w
  239. }
  240.  
  241. proc tixPanedWindow:delete {w name} {
  242.     upvar #0 $w data
  243.  
  244.     if {![winfo exists $w.$name]} {
  245.     error "Pane $name does not exist"
  246.     }
  247.  
  248.  
  249.     if {!$data($name,forgotten)} {
  250.     set items ""
  251.     foreach item $data(items) {
  252.         if {$item != $name} {
  253.         lappend items $item
  254.         }
  255.     }
  256.     set data(items) $items
  257.     incr data(nItems) -1
  258.  
  259.     set i $data(nItems)
  260.     if {$i > 0} {
  261.         destroy $data(btn,$i)
  262.         destroy $data(sep,$i)
  263.         unset data(btn,$i)
  264.         unset data(sep,$i)
  265.     }
  266.     }
  267.     unset data($name,allowresize)
  268.     unset data($name,expand)
  269.     unset data($name,forgotten)
  270.     unset data($name,max)
  271.     unset data($name,min)
  272.     unset data($name,rsize)
  273.     unset data($name,size)
  274.     unset data(w:$name)
  275.     destroy $w.$name
  276.  
  277.     tixPanedWindow:RepackWhenIdle $w
  278. }
  279.  
  280. proc tixPanedWindow:paneconfigure {w name args} {
  281.     upvar #0 $w data
  282.  
  283.     if {![info exists data($name,size)]} {
  284.     error "pane \"$name\" does not exist in $w"
  285.     }
  286.  
  287.     set len [llength $args]
  288.  
  289.     if {$len == 0} {
  290.     set value [$data(w:$name) configure]
  291.     lappend value [list -allowresize "" "" "" $data($name,allowresize)]
  292.     lappend value [list -expand "" "" "" $data($name,expand)]
  293.     lappend value [list -max "" "" "" $data($name,max)]
  294.     lappend value [list -min "" "" "" $data($name,min)]
  295.     lappend value [list -size "" "" "" $data($name,size)]
  296.     return $value
  297.     }
  298.  
  299.     if {$len == 1} {
  300.     case [lindex $args 0] {
  301.         -allowresize {
  302.         return [list -allowresize "" "" "" $data($name,allowresize)]
  303.         }
  304.         -expand {
  305.         return [list -expand "" "" "" $data($name,expand)]
  306.         }
  307.         -min {
  308.         return [list -min "" "" "" $data($name,min)]
  309.         }
  310.         -max {
  311.         return [list -max "" "" "" $data($name,max)]
  312.         }
  313.         -size {
  314.         return [list -size "" "" "" $data($name,size)]
  315.         }
  316.         default {
  317.         return [$data(w:$name) configure [lindex $args 0]]
  318.         }
  319.     }
  320.     }
  321.  
  322.     # By default handle each of the options
  323.     #
  324.     set option(-allowresize) $data($name,allowresize)
  325.     set option(-expand)      $data($name,expand)
  326.     set option(-min)         $data($name,min)
  327.     set option(-max)         $data($name,max)
  328.     set option(-size)        $data($name,size)
  329.  
  330.     tixHandleOptions -nounknown option {-allowresize -expand -max -min -size} \
  331.     $args
  332.  
  333.     #
  334.     # the widget options
  335.     set new_args ""
  336.     tixForEach {flag value} $args {
  337.     case $flag {
  338.         {-expand -min -max -allowresize -size} {
  339.  
  340.         }
  341.         default {
  342.         lappend new_args $flag
  343.         lappend new_args $value
  344.         }
  345.     }
  346.     }
  347.  
  348.     if {[llength $new_args] >= 2} {
  349.     eval $data(w:$name) configure $new_args
  350.     }
  351.  
  352.     #
  353.     # The add-on options
  354.     set data($name,allowresize) $option(-allowresize)
  355.     set data($name,expand)      $option(-expand)
  356.     set data($name,max)         $option(-max)
  357.     set data($name,min)         $option(-min)
  358.     set data($name,rsize)       $option(-size)
  359.     set data($name,size)        $option(-size)
  360.  
  361.     # 
  362.     # Integrity check
  363.     if {$data($name,expand) < 0} {
  364.     set data($name,expand) 0
  365.     }
  366.     if {$data($name,size) < $data($name,min)} {
  367.     set data($name,size) $data($name,min)
  368.     }
  369.     if {$data($name,size) > $data($name,max)} {
  370.     set data($name,size) $data($name,max)
  371.     }
  372.  
  373.     tixPanedWindow:RepackWhenIdle $w
  374.     return ""
  375. }
  376.  
  377. proc tixPanedWindow:panecget {w name option} {
  378.     upvar #0 $w data
  379.  
  380.     if {![info exists data($name,size)]} {
  381.     error "pane \"$name\" does not exist in $w"
  382.     }
  383.  
  384.     case $option {
  385.     {-min -max -allowresize -size} {
  386.         regsub \\\- $option "" option
  387.         return "$data($name,$option)"
  388.     }
  389.     default {
  390.         return [$data(w:$name) cget $option]
  391.     }
  392.     }
  393. }
  394.  
  395. # return the name of all panes
  396. proc tixPanedWindow:panes {w} {
  397.     upvar #0 $w data
  398.  
  399.     return $data(items)
  400. }
  401.  
  402. # set the size of a pane, specifying which direction it should
  403. # grow/shrink
  404. proc tixPanedWindow:setsize {w item size {direction next}} {
  405.     upvar #0 $w data
  406.  
  407.     set posn [lsearch $data(items) $item]
  408.     if {$posn == -1} {
  409.     error "pane \"$item\" does not exist"
  410.     }
  411.  
  412.     set diff [expr $size - $data($item,size)]
  413.     if {$diff == 0} {
  414.     return
  415.     }
  416.  
  417.     if {$posn == 0 && $direction == "prev"} {
  418.     set direction next
  419.     }
  420.     if {$posn == [expr $data(nItems)-1] && $direction == "next"} {
  421.     set direction prev
  422.     }
  423.  
  424.     set rx [winfo rootx $data(w:$item)]
  425.     if {$direction == "prev"} {
  426.     set rx [expr $rx - $diff]
  427.     } else {
  428.     set rx [expr $rx + [winfo width $data(w:$item)] + $diff]
  429.     incr posn
  430.     }
  431.  
  432.     # Set up the panedwin in a proper state
  433.     #
  434.     tixPanedWindow:BtnDown $w $posn 1
  435.     tixPanedWindow:BtnMove $w $posn $rx 1
  436.     tixPanedWindow:BtnUp $w $posn 1
  437.  
  438.     return $data(items)
  439. }
  440.  
  441. #----------------------------------------------------------------------
  442. # PrivateMethods:
  443. #----------------------------------------------------------------------
  444.  
  445. proc tixPanedWindow:AddSeparator {w} {
  446.     upvar #0 $w data
  447.  
  448.     set n [expr $data(nItems)-1]
  449.  
  450.     if {$data(-orientation) == "vertical"} {
  451.     set data(sep,$n) [frame $w.sep$n -relief sunken \
  452.         -bd 1 -height 2 -width 10000 -bg $data(-separatorbg)]
  453.     } else {
  454.     set data(sep,$n) [frame $w.sep$n -relief sunken \
  455.         -bd 1 -width 2 -height 10000 -bg $data(-separatorbg)]
  456.     }
  457.  
  458.     set data(btn,$n) [frame $w.btn$n -relief raised \
  459.     -bd 1 -width 9 -height 9 \
  460.     -bg $data(-handlebg)]
  461.  
  462.     if {$data(-orientation) == "vertical"} {
  463.     set cursor sb_v_double_arrow
  464.     } else {
  465.     set cursor sb_h_double_arrow
  466.     }
  467.     $data(sep,$n) config -cursor $cursor
  468.     $data(btn,$n) config -cursor $cursor
  469.  
  470.     foreach wid "$data(btn,$n) $data(sep,$n)" {
  471.     bind $wid \
  472.         <ButtonPress-1>   "tixPanedWindow:BtnDown $w $n"
  473.     bind $wid \
  474.         <ButtonRelease-1> "tixPanedWindow:BtnUp   $w $n"
  475.     bind $wid \
  476.         <Any-Enter>       "tixPanedWindow:HighlightBtn $w $n"
  477.     bind $wid \
  478.         <Any-Leave>       "tixPanedWindow:DeHighlightBtn $w $n"
  479.     }
  480.  
  481.     if {$data(-orientation) == "vertical"} {
  482.     bind  $data(btn,$n) <B1-Motion> \
  483.         "tixPanedWindow:BtnMove $w $n %Y"
  484.     } else {
  485.     bind  $data(btn,$n) <B1-Motion> \
  486.         "tixPanedWindow:BtnMove $w $n %X"
  487.     }
  488.  
  489.     if {$data(-orientation) == "vertical"} {
  490. #    place $data(btn,$n) -relx 0.90 -y [expr "$data(totalsize)-5"]
  491. #    place $data(sep,$n) -x 0 -y [expr "$data(totalsize)-1"] -relwidth 1
  492.     } else {
  493. #    place $data(btn,$n) -rely 0.90 -x [expr "$data(totalsize)-5"]
  494. #    place $data(sep,$n) -y 0 -x [expr "$data(totalsize)-1"] -relheight 1
  495.     }
  496. }
  497.  
  498. proc tixPanedWindow:BtnDown {w item {fake 0}} {
  499.     upvar #0 $w data
  500.  
  501.     if {$data(-orientation) == "vertical"} {
  502.     set spec -height
  503.     } else {
  504.     set spec -width
  505.     }
  506.  
  507.     if {!$fake} {
  508.     for {set i 1} {$i < $data(nItems)} {incr i} {
  509.         $data(sep,$i) config -bg $data(-separatoractivebg) $spec 1
  510.     }
  511.     update idletasks
  512.     $data(btn,$item) config -relief sunken
  513.     }
  514.  
  515.     tixPanedWindow:GetMotionLimit $w $item $fake
  516.  
  517.     if {!$fake} {
  518.     grab -global $data(btn,$item)
  519.     }
  520.     set data(movePending) 0
  521. }
  522.  
  523. proc tixPanedWindow:Min2 {a b} {
  524.     if {$a < $b} {
  525.     return $a
  526.     } else {
  527.     return $b
  528.     }
  529. }
  530.  
  531. proc tixPanedWindow:GetMotionLimit {w item fake} {
  532.     upvar #0 $w data
  533.  
  534.     set curBefore 0
  535.     set minBefore 0
  536.     set maxBefore 0
  537.  
  538.     for {set i 0} {$i < $item} {incr i} {
  539.     set name [lindex $data(items) $i]
  540.     incr curBefore $data($name,size)
  541.     incr minBefore $data($name,min)
  542.     incr maxBefore $data($name,max)
  543.     }
  544.  
  545.     set curAfter 0
  546.     set minAfter 0
  547.     set maxAfter 0
  548.     while {$i < $data(nItems)} {
  549.     set name [lindex $data(items) $i]
  550.     incr curAfter $data($name,size)
  551.     incr minAfter $data($name,min)
  552.     incr maxAfter $data($name,max)
  553.     incr i
  554.     }
  555.  
  556.     set beforeToGo [tixPanedWindow:Min2 \
  557.         [expr "$curBefore-$minBefore"] [expr "$maxAfter-$curAfter"]]
  558.  
  559.     set afterToGo [tixPanedWindow:Min2 \
  560.         [expr "$curAfter-$minAfter"] [expr "$maxBefore-$curBefore"]]
  561.  
  562.     set data(beforeLimit) [expr "$curBefore-$beforeToGo"]
  563.     set data(afterLimit)  [expr "$curBefore+$afterToGo"]
  564.     set data(curSize)     $curBefore
  565.  
  566.     if {!$fake} {
  567.     tixPanedWindow:PlotHandles $w 1
  568.     }
  569. }
  570.  
  571. # Compress the motion so that update is quick even on slow machines
  572. #
  573. # rootp = root position (either rootx or rooty)
  574. proc tixPanedWindow:BtnMove {w item rootp {fake 0}} {
  575.     upvar #0 $w data
  576.  
  577.     set data(rootp) $rootp
  578.  
  579.     if {$fake} {
  580.     tixPanedWindow:BtnMoveCompressed $w $item $fake
  581.     } else {
  582.     if {$data(movePending) == 0} {
  583.         after 2 tixPanedWindow:BtnMoveCompressed $w $item
  584.         set data(movePending) 1
  585.     }
  586.     } 
  587. }
  588.  
  589. proc tixPanedWindow:BtnMoveCompressed {w item {fake 0}} {
  590.     if {![winfo exists $w]} {
  591.     return
  592.     }
  593.  
  594.     upvar #0 $w data
  595.  
  596.     if {$data(-orientation) == "vertical"} {
  597.     set p [expr $data(rootp)-[winfo rooty $w]]
  598.     } else {
  599.     set p [expr $data(rootp)-[winfo rootx $w]]
  600.     }
  601.  
  602.     if {$p == $data(curSize)} {
  603.     set data(movePending) 0
  604.     return
  605.     }
  606.  
  607.     if {$p < $data(beforeLimit)} {
  608.     set p $data(beforeLimit)
  609.     }
  610.     if {$p >= $data(afterLimit)} {
  611.     set p $data(afterLimit)
  612.     }
  613.     tixPanedWindow:CalculateChange $w $item $p $fake
  614.  
  615.     if {!$fake} {
  616.     # Force the redraw to happen
  617.     #
  618.     update idletasks
  619.     }
  620.     set data(movePending) 0
  621. }
  622.  
  623. # Calculate the change in response to mouse motions
  624. #
  625. proc tixPanedWindow:CalculateChange {w item p {fake 0}} {
  626.     upvar #0 $w data
  627.  
  628.     if {$p < $data(curSize)} {
  629.     tixPanedWindow:MoveBefore $w $item $p
  630.     } elseif {$p > $data(curSize)} {
  631.     tixPanedWindow:MoveAfter $w $item $p
  632.     }
  633.  
  634.     if {!$fake} {
  635.     tixPanedWindow:PlotHandles $w 1
  636.     }
  637. }
  638.  
  639. proc tixPanedWindow:MoveBefore {w item p} {
  640.     upvar #0 $w data
  641.  
  642.     set n [expr "$data(curSize)-$p"]
  643.  
  644.     # Shrink the frames before
  645.     #
  646.     set from [expr $item-1]
  647.     set to   0
  648.     tixPanedWindow:Iterate $w $from $to tixPanedWindow:Shrink $n
  649.  
  650.     # Adjust the frames after
  651.     #
  652.     set from $item
  653.     set to   [expr "$data(nItems)-1"]
  654.     tixPanedWindow:Iterate $w $from $to tixPanedWindow:Grow $n
  655.  
  656.     set data(curSize) $p
  657. }
  658.  
  659. proc tixPanedWindow:MoveAfter {w item p} {
  660.     upvar #0 $w data
  661.  
  662.     set n    [expr "$p-$data(curSize)"]
  663.  
  664.     # Shrink the frames after
  665.     #
  666.     set from $item
  667.     set to   [expr "$data(nItems)-1"]
  668.     tixPanedWindow:Iterate $w $from $to tixPanedWindow:Shrink $n
  669.  
  670.     # Graw the frame before
  671.     #
  672.     set from [expr $item-1]
  673.     set to   0
  674.     tixPanedWindow:Iterate $w $from $to tixPanedWindow:Grow $n
  675.  
  676.     set data(curSize) $p
  677. }
  678.  
  679. proc tixPanedWindow:CancleLines {w} {
  680.     upvar #0 $w data
  681.  
  682.     if [info exists data(lines)] {
  683.     foreach line $data(lines) {
  684.         set x1 [lindex $line 0]
  685.         set y1 [lindex $line 1]
  686.         set x2 [lindex $line 2]
  687.         set y2 [lindex $line 3]
  688.  
  689.         tixTmpLine $x1 $y1 $x2 $y2 $w
  690.     }
  691.  
  692.     catch {unset data(lines)}
  693.     }
  694. }
  695.  
  696. proc tixPanedWindow:PlotHandles {w transient} {
  697.     upvar #0 $w data
  698.  
  699.     set totalsize 0
  700.     set i 0
  701.  
  702.     if {$data(-orientation) == "vertical"} {
  703.     set btnp [expr [winfo width $w]-13]
  704.     } else {
  705.     set h [winfo height $w]
  706.     if {$h > 18} {
  707.         set btnp 9
  708.     } else {
  709.         set btnp [expr $h-9]
  710.     }
  711.     }
  712.  
  713.     set firstpane [lindex $data(items) 0]
  714.     set totalsize $data($firstpane,size)
  715.  
  716.     if {$transient} {
  717.     tixPanedWindow:CancleLines $w
  718.     set data(lines) ""
  719.     }
  720.  
  721.     for {set i 1} {$i < $data(nItems)} {incr i} {
  722.     if {! $transient} {
  723.         if {$data(-orientation) == "vertical"} {
  724.         place $data(btn,$i) -x $btnp -y [expr "$totalsize-4"]
  725.         place $data(sep,$i) -x 0 -y [expr "$totalsize-1"] -relwidth 1
  726.         } else {
  727.         place $data(btn,$i) -y $btnp -x [expr "$totalsize-5"]
  728.         place $data(sep,$i) -y 0 -x [expr "$totalsize-1"] -relheight 1
  729.         }
  730.     } else {
  731.         if {$data(-orientation) == "vertical"} {
  732.         set x1 [winfo rootx $w]
  733.         set x2 [expr $x1 + [winfo width $w]]
  734.         set y  [expr $totalsize-1+[winfo rooty $w]]
  735.  
  736.         tixTmpLine $x1 $y $x2 $y $w
  737.         lappend data(lines) [list $x1 $y $x2 $y]
  738.         } else {
  739.         set y1 [winfo rooty $w]
  740.         set y2 [expr $y1 + [winfo height $w]]
  741.         set x  [expr $totalsize-1+[winfo rootx $w]]
  742.  
  743.         tixTmpLine $x $y1 $x $y2 $w
  744.         lappend data(lines) [list $x $y1 $x $y2]
  745.         }
  746.     }
  747.  
  748.     set name [lindex $data(items) $i]
  749.     incr totalsize $data($name,size)
  750.     }
  751. }
  752.  
  753. proc tixPanedWindow:BtnUp {w item {fake 0}} {
  754.     upvar #0 $w data
  755.  
  756.     if {!$fake} {
  757.     tixPanedWindow:CancleLines $w
  758.     }
  759.  
  760.     tixPanedWindow:UpdateSizes $w
  761.  
  762.     if {!$fake} {
  763.     $data(btn,$item) config -relief raised
  764.     grab release $data(btn,$item)
  765.     }
  766. }
  767.  
  768.  
  769. proc tixPanedWindow:HighlightBtn {w item} {
  770.     upvar #0 $w data
  771.  
  772.     $data(btn,$item) config -background $data(-handleactivebg)
  773. }
  774.  
  775. proc tixPanedWindow:DeHighlightBtn {w item} {
  776.     upvar #0 $w data
  777.  
  778.     $data(btn,$item) config -background $data(-handlebg)
  779. }
  780.  
  781. #----------------------------------------------------------------------
  782. #
  783. #
  784. # Geometry management routines
  785. #
  786. #
  787. #----------------------------------------------------------------------
  788.  
  789. # update the sizes of each pane according to the data($name,size) variables
  790. #
  791. proc tixPanedWindow:UpdateSizes {w} {
  792.     upvar #0 $w data
  793.  
  794.     set data(totalsize) 0
  795.  
  796.     set mw [winfo width  $w]
  797.     set mh [winfo height $w]
  798.  
  799.     for {set i 0} {$i < $data(nItems)} {incr i} {
  800.     set name [lindex $data(items) $i]
  801.  
  802.     if {$data($name,size) > 0} {
  803.         if {$data(-orientation) == "vertical"} {
  804.         tixMoveResizeWindow $w.$name 0 $data(totalsize) \
  805.             $mw $data($name,size)
  806.         tixMapWindow $w.$name
  807.         raise $w.$name
  808.         } else {
  809.         tixMoveResizeWindow $w.$name $data(totalsize) 0 \
  810.             $data($name,size) $mh
  811.         tixMapWindow $w.$name
  812.         raise $w.$name
  813.         }
  814.     } else {
  815.         tixUnmapWindow $w.$name
  816.     }
  817.     incr data(totalsize) $data($name,size)
  818.     }
  819.  
  820.     # Reset the color and width of the separator
  821.     #
  822.     if {$data(-orientation) == "vertical"} {
  823.     set spec -height
  824.     } else {
  825.     set spec -width
  826.     }
  827.  
  828.     for {set i 1} {$i < $data(nItems)} {incr i} {
  829.     $data(sep,$i) config -bg $data(-separatorbg) $spec 2
  830.     raise $data(sep,$i)
  831.     raise $data(btn,$i)
  832.     }
  833.  
  834.  
  835.     # Invoke the callback command
  836.     #
  837.     if {$data(-command) != ""} {
  838.     set sizes ""
  839.     foreach item $data(items) {
  840.         lappend sizes $data($item,size)
  841.     }
  842.     set bind(specs) ""
  843.     tixEvalCmdBinding $w $data(-command) bind [list $sizes]
  844.     }
  845. }
  846.  
  847. proc tixPanedWindow:GetNaturalSizes {w} {
  848.     upvar #0 $w data
  849.  
  850.     set data(totalsize) 0
  851.     set totalreq 0
  852.  
  853.     if {$data(-orientation) == "vertical"} {
  854.     set majorspec height
  855.     set minorspec width
  856.     } else {
  857.     set majorspec width
  858.     set minorspec height
  859.     }
  860.  
  861.     set minorsize 0
  862.     foreach name $data(items) {
  863.     if {[winfo manager $w.$name] != "tixGeometry"} {
  864.         error "Geometry management error: pane \"$w.$name\" cannot be managed by \"[winfo manager $w.$name]\"\nhint: delete the line \"[winfo manager $w.$name] $w.$name ...\" from your program"
  865.     }
  866.  
  867.     # set the minor size
  868.     #
  869.     set req_minor [winfo req$minorspec $w.$name]
  870.  
  871.     if {$req_minor > $minorsize} {
  872.         set minorsize $req_minor
  873.     }
  874.  
  875.     # Check the natural size against the max, min requirements.
  876.     # Change the natural size if necessary
  877.     #
  878.     if {$data($name,size) <= 1} {
  879.         set data($name,size) [winfo req$majorspec $w.$name]
  880.     }
  881.  
  882.     if {$data($name,size) > 1} {
  883.         # If we get zero maybe the widget was not initialized yet ...
  884.         #
  885.         # %% hazard : what if the window is really 1x1?
  886.         #
  887.         if {$data($name,size) < $data($name,min)} {
  888.         set data($name,size) $data($name,min)
  889.         }
  890.         if {$data($name,size) > $data($name,max)} {
  891.         set data($name,size) $data($name,max)
  892.         }
  893.     }
  894.  
  895.     # kludge: because a frame always returns req size of {1,1} before
  896.     # the packer processes it, we do the following to mark the
  897.     # pane as "size unknown"
  898.     #
  899. #    if {$data($name,size) == 1 && ![winfo ismapped $w.$name]} {
  900. #        set data($name,size) 0
  901. #    }
  902.  
  903.     # Add up the total size
  904.     #
  905.     incr data(totalsize) $data($name,size)
  906.  
  907.     # Find out the request size
  908.     #
  909.     if {$data($name,rsize) == 0} {
  910.         set rsize [winfo req$majorspec $w.$name]
  911.     } else {
  912.         set rsize $data($name,rsize)
  913.     }
  914.  
  915.     if {$rsize < $data($name,min)} {
  916.         set rsize $data($name,min)
  917.     }
  918.     if {$rsize > $data($name,max)} {
  919.         set rsize $data($name,max)
  920.     }
  921.  
  922.     incr totalreq $rsize
  923.     }
  924.  
  925.     if {$data(-orientation) == "vertical"} {
  926.     return "$minorsize $totalreq"
  927.     } else {
  928.     return "$totalreq $minorsize"
  929.     }
  930. }
  931.  
  932. #--------------------------------------------------
  933. # Handling resize
  934. #--------------------------------------------------
  935. proc tixPanedWindow:ClientGeomProc {w type client} {
  936.     tixPanedWindow:RepackWhenIdle $w
  937. }
  938.  
  939. #
  940. # This monitor the sizes of the master window
  941. #
  942. proc tixPanedWindow:MasterGeomProc {w master} {
  943.     tixPanedWindow:RepackWhenIdle $w
  944. }
  945.  
  946. proc tixPanedWindow:RepackWhenIdle {w} {
  947.     if {![winfo exist $w]} {
  948.     return
  949.     }
  950.     upvar #0 $w data
  951.  
  952.     if {$data(repack) == 0} {
  953.     tixWidgetDoWhenIdle tixPanedWindow:Repack $w
  954.     set data(repack) 1
  955.     }
  956. }
  957.  
  958. #
  959. # This monitor the sizes of the master window
  960. #
  961. proc tixPanedWindow:Repack {w} {
  962.     upvar #0 $w data
  963.  
  964.     # Calculate the desired size of the master
  965.     #
  966.     set dim [tixPanedWindow:GetNaturalSizes $w]
  967.  
  968.     if {$data(-width) != 0} {
  969.     set mreqw $data(-width)
  970.     } else {
  971.     set mreqw [lindex $dim 0]
  972.     }
  973.  
  974.     if {$data(-height) != 0} {
  975.     set mreqh $data(-height)
  976.     } else {
  977.     set mreqh [lindex $dim 1]
  978.     }
  979.  
  980.     if !$data(-dynamicgeometry) {
  981.     if {$mreqw < $data(maxReqW)} {
  982.         set mreqw $data(maxReqW)
  983.     }
  984.     if {$mreqh < $data(maxReqH)} {
  985.         set mreqh $data(maxReqH)
  986.     }
  987.     set data(maxReqW) $mreqw
  988.     set data(maxReqH) $mreqh
  989.     }
  990.     if {$mreqw != [winfo reqwidth $w] || $mreqh != [winfo reqheight $w] } {
  991.     if {![info exists data(counter)]} {
  992.         set data(counter) 0
  993.     }
  994.     if {$data(counter) < 50} {
  995.         incr data(counter)
  996.         tixGeometryRequest $w $mreqw $mreqh
  997.         tixWidgetDoWhenIdle tixPanedWindow:Repack $w
  998.         set data(repack) 1
  999.         return
  1000.     }
  1001.     }
  1002.  
  1003.     set data(counter) 0
  1004.  
  1005.     if {$data(nItems) == 0} {
  1006.     set data(repack) 0
  1007.     return
  1008.     }
  1009.  
  1010.     tixWidgetDoWhenIdle tixPanedWindow:DoRepack $w
  1011. }
  1012.  
  1013. proc tixPanedWindow:DoRepack {w} {
  1014.     upvar #0 $w data
  1015.  
  1016.     if {$data(-orientation) == "vertical"} {
  1017.     set newSize [winfo height $w]
  1018.     } else {
  1019.     set newSize [winfo width $w]
  1020.     }
  1021.  
  1022.     if {$newSize <= 1} {
  1023.     # Probably this window is too small to see anyway
  1024.     # %%Kludge: I don't know if this always work.
  1025.     #
  1026.     set data(repack) 0
  1027.     return
  1028.     }
  1029.  
  1030.     set totalExp 0
  1031.     foreach name $data(items) {
  1032.     set totalExp [expr $totalExp + $data($name,expand)]
  1033.     }
  1034.  
  1035.     if {$newSize > $data(totalsize)} {
  1036.     # Grow
  1037.     #
  1038.     set toGrow [expr "$newSize-$data(totalsize)"]
  1039.  
  1040.     set p [llength $data(items)]
  1041.     foreach name $data(items) {
  1042.         set toGrow [tixPanedWindow:xGrow $w $name $toGrow $totalExp $p]
  1043.         if {$toGrow > 0} {
  1044.         set totalExp [expr $totalExp-$data($name,expand)]
  1045.         incr p -1
  1046.         } else {
  1047.         break
  1048.         }
  1049.     }
  1050.     } else {
  1051.     # Shrink
  1052.     #
  1053.     set toShrink [expr "$data(totalsize)-$newSize"]
  1054.  
  1055.     set usedSize 0
  1056.     foreach name $data(items) {
  1057.         set toShrink [tixPanedWindow:xShrink $w $name $toShrink \
  1058.         $totalExp $newSize $usedSize]
  1059.         if {$toShrink > 0} {
  1060.         set totalExp [expr $totalExp-$data($name,expand)]
  1061.         incr usedSize $data($name,size)
  1062.         } else {
  1063.         break
  1064.         }
  1065.     }
  1066.     }
  1067.  
  1068.     tixPanedWindow:UpdateSizes $w
  1069.     tixPanedWindow:PlotHandles $w 0
  1070.  
  1071.     set data(repack) 0
  1072. }
  1073.  
  1074. #--------------------------------------------------
  1075. # Shrink and grow items
  1076. #--------------------------------------------------
  1077. #   toGrow: how much free area to grow into
  1078. #        p: == 1 if $name is the last in the list of items
  1079. # totalExp: used to calculate the amount of the free area that this
  1080. #        window can grow into
  1081. #
  1082. proc tixPanedWindow:xGrow {w name toGrow totalExp p} {
  1083.     upvar #0 $w data
  1084.  
  1085.     if {$p == 1} {
  1086.     set canGrow $toGrow
  1087.     } else {
  1088.     if {$totalExp == 0} {
  1089.         set canGrow 0
  1090.     } else {
  1091.         set canGrow [expr int($toGrow * $data($name,expand) / $totalExp)]
  1092.     }
  1093.     }
  1094.  
  1095.     if {[expr $canGrow + $data($name,size)] > $data($name,max)} {
  1096.     set canGrow [expr $data($name,max) - $data($name,size)]
  1097.     }
  1098.  
  1099.     incr data($name,size) $canGrow
  1100.     incr toGrow -$canGrow
  1101.  
  1102.     return $toGrow
  1103. }
  1104.  
  1105. proc tixPanedWindow:xShrink {w name toShrink totalExp newSize usedSize} {
  1106.     upvar #0 $w data
  1107.  
  1108.     if {$totalExp == 0} {
  1109.     set canShrink 0
  1110.     } else {
  1111.     set canShrink [expr int($toShrink * $data($name,expand) / $totalExp)]
  1112.     }
  1113.  
  1114.     if {[expr $data($name,size) - $canShrink] < $data($name,min)} {
  1115.     set canShrink [expr $data($name,size) -$data($name,min)]
  1116.     }
  1117.     if {[expr $usedSize + $data($name,size) - $canShrink] > $newSize} {
  1118.     set data($name,size) [expr $newSize - $usedSize]
  1119.     return 0
  1120.     } else {
  1121.     incr data($name,size) -$canShrink
  1122.     incr toShrink -$canShrink
  1123.  
  1124.     return $toShrink
  1125.     }
  1126. }
  1127.  
  1128. #--------------------------------------------------
  1129. # Shrink and grow items
  1130. #--------------------------------------------------
  1131. proc tixPanedWindow:Shrink {w name n} {
  1132.     upvar #0 $w data
  1133.  
  1134.     set canShrink [expr "$data($name,size) - $data($name,min)"]
  1135.  
  1136.     if {$canShrink > $n} {
  1137.     incr data($name,size) -$n
  1138.     return 0
  1139.     } elseif {$canShrink > 0} {
  1140.     set data($name,size) $data($name,min)
  1141.     incr n -$canShrink
  1142.     }
  1143.     return $n
  1144. }
  1145.  
  1146. proc tixPanedWindow:Grow {w name n} {
  1147.     upvar #0 $w data
  1148.  
  1149.     set canGrow [expr "$data($name,max) - $data($name,size)"]
  1150.  
  1151.     if {$canGrow > $n} {
  1152.     incr data($name,size) $n
  1153.     return 0
  1154.     } elseif {$canGrow > 0} {
  1155.     set data($name,size) $data($name,max)
  1156.     incr n -$canGrow
  1157.     }
  1158.  
  1159.     return $n
  1160. }
  1161.  
  1162. proc tixPanedWindow:Iterate {w from to proc n} {
  1163.     upvar #0 $w data
  1164.  
  1165.     if {$from <= $to} {
  1166.     for {set i $from} {$i <= $to} {incr i} {
  1167.         set n [$proc $w [lindex $data(items) $i] $n]
  1168.         if {$n == 0} {
  1169.         break
  1170.         }
  1171.     }
  1172.     } else {
  1173.     for {set i $from} {$i >= $to} {incr i -1} {
  1174.         set n [$proc $w [lindex $data(items) $i] $n]
  1175.         if {$n == 0} {
  1176.         break
  1177.         }
  1178.     }
  1179.     }
  1180. }
  1181.